#include <asm/io.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
/***************************************************************
st7701 spi 初始化驱动.
文件名     　　：st7701s.c
作者          : 任晓朋
版本          : V1.0
描述          : 初始化配置ST7701s屏。
其他          : 无
时间　　　　　　：2022.7.24
***************************************************************/
#define LED_MAJOR 200     /* 主设备号 */
#define LED_NAME "st7701" /* 设备名字 */

// 3线spi用到的三个IO口和一个RET管脚
#define SPI_DSIO 32  // PB0
#define SPI_SCLK 33  // PB1
#define SPI_CS 36    // PB4
#define RST_PANEL 37 // PB5

// 单字节发送
static void spi_st7701s_SendData(unsigned char i) {
  unsigned char n;
  for (n = 0; n < 8; n++) {
    if (i & 0x80) {
      //      printf("this bit is 1 \r\n");
      gpio_set_value(SPI_DSIO, 1);
    } else {
      //        printf("this bit is 0 \r\n");
      gpio_set_value(SPI_DSIO, 0);
    }

    i <<= 1;

    gpio_set_value(SPI_SCLK, 0);
    udelay(1);
    gpio_set_value(SPI_SCLK, 1);
    udelay(1);
  }
}
/*
static unsigned char Spi_St7701s_ReadByte(unsigned char id)
{
    unsigned char i,tmp = 0;


    gpio_set_value(SPI_CS, 0);
    gpio_set_value(SPI_DSIO, 0);



    gpio_set_value(SPI_SCLK, 0);
    udelay(1);
    gpio_set_value(SPI_SCLK, 1);
    udelay(1);


    spi_st7701s_SendData(id);
    //先写寄存器地址0x04
    gpio_set_value(SPI_SCLK, 0);
    gpio_set_value(SPI_DSIO, 1);//设为高阻态输入模式？

    udelay(1);

    gpio_direction_input(SPI_DSIO);
    for(i = 0;i < 8;i++)

    {
        gpio_set_value(SPI_SCLK, 1);

        tmp <<= 1; //移位


       // printf("value is %d \r\n",value);
        if(gpio_get_value(SPI_DSIO))
        {

            tmp |= 1; //读取一位数据
        }

        gpio_set_value(SPI_SCLK, 0);

    }
    gpio_direction_output(SPI_DSIO,1);


    gpio_set_value(SPI_SCLK, 1);
    udelay(1);
    gpio_set_value(SPI_SCLK, 0);

    gpio_set_value(SPI_DSIO, 1);

    gpio_set_value(SPI_CS, 1);

    return tmp; //返回数据
}
*/

// 写指令
static void SPI_WriteComm(unsigned char i) {

  gpio_set_value(SPI_CS, 0);

  gpio_set_value(SPI_DSIO, 0);

  gpio_set_value(SPI_SCLK, 0);

  udelay(1);
  gpio_set_value(SPI_SCLK, 1);
  udelay(1);

  spi_st7701s_SendData(i);

  gpio_set_value(SPI_CS, 1);
}

// 写数据
static void SPI_WriteData(unsigned char i) {

  gpio_set_value(SPI_CS, 0);

  gpio_set_value(SPI_DSIO, 1);

  gpio_set_value(SPI_SCLK, 0);
  udelay(1);
  gpio_set_value(SPI_SCLK, 1);
  udelay(1);

  spi_st7701s_SendData(i);

  gpio_set_value(SPI_CS, 1);
}
// 初始化
void ST7701S_Init(void) {

  // unsigned char ID1,ID2,ID3;

  gpio_request(SPI_DSIO, "SPI_DSIO");
  gpio_request(SPI_SCLK, "SPI_SCLK");
  gpio_request(SPI_CS, "SPI_CS");
  gpio_request(RST_PANEL, "RST_PANEL");

  gpio_direction_output(SPI_DSIO, 1);
  gpio_direction_output(SPI_SCLK, 1);
  gpio_direction_output(SPI_CS, 1);
  gpio_direction_output(RST_PANEL, 1);

  gpio_set_value(RST_PANEL, 0);
  mdelay(200);
  gpio_set_value(RST_PANEL, 1);
  mdelay(200);

  //    ID1 = Spi_St7701s_ReadByte(0xDA);
  //    ID2 = Spi_St7701s_ReadByte(0xDB);
  //    ID3 = Spi_St7701s_ReadByte(0xDC);
  //    printk("sssss\r\n");
  //    printk("ssss:0x%d 0x%d 0x%d\r\n", ID1,ID2,ID3);

  //  HW_Reset();               //VBP>=11, VFP>=7

  mdelay(120);

  SPI_WriteComm(0xFF);
  SPI_WriteData(0x77);
  SPI_WriteData(0x01);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x10);

  SPI_WriteComm(0xC0);
  SPI_WriteData(0x3B); // 屏的分辨率
  SPI_WriteData(0x00);

  SPI_WriteComm(0xC1);
  SPI_WriteData(0x0B); // VBP 如果配置为>0B屏幕上边有黑边显示不完整
  SPI_WriteData(0x02);

  SPI_WriteComm(0xC2);
  SPI_WriteData(0x07);
  SPI_WriteData(0x02);

  SPI_WriteComm(
      0xC3); // 配置工作模式为DE模式，供应商给的驱动源码并没有设置该 地址 。
  SPI_WriteData(0x0C);
  SPI_WriteData(0x02);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xCC);
  SPI_WriteData(0x10);

  SPI_WriteComm(0xCD); // RGB format
  SPI_WriteData(0x08); // 用565时屏蔽    666打开

  SPI_WriteComm(0xB0); // IPS
  SPI_WriteData(0x00); // 255
  SPI_WriteData(0x11); // 251
  SPI_WriteData(0x16); // 247  down
  SPI_WriteData(0x0e); // 239
  SPI_WriteData(0x11); // 231
  SPI_WriteData(0x06); // 203
  SPI_WriteData(0x05); // 175
  SPI_WriteData(0x09); // 147
  SPI_WriteData(0x08); // 108
  SPI_WriteData(0x21); // 80
  SPI_WriteData(0x06); // 52
  SPI_WriteData(0x13); // 24
  SPI_WriteData(0x10); // 16
  SPI_WriteData(0x29); // 8    down
  SPI_WriteData(0x31); // 4
  SPI_WriteData(0x18); // 0

  SPI_WriteComm(0xB1); //  IPS
  SPI_WriteData(0x00); //  255
  SPI_WriteData(0x11); //  251
  SPI_WriteData(0x16); //  247   down
  SPI_WriteData(0x0e); //  239
  SPI_WriteData(0x11); //  231
  SPI_WriteData(0x07); //  203
  SPI_WriteData(0x05); //  175
  SPI_WriteData(0x09); //  147
  SPI_WriteData(0x09); //  108
  SPI_WriteData(0x21); //  80
  SPI_WriteData(0x05); //  52
  SPI_WriteData(0x13); //  24
  SPI_WriteData(0x11); //  16
  SPI_WriteData(0x2a); //  8  down
  SPI_WriteData(0x31); //  4
  SPI_WriteData(0x18); //  0

  SPI_WriteComm(0xFF);
  SPI_WriteData(0x77);
  SPI_WriteData(0x01);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x11);

  SPI_WriteComm(0xB0); // VOP  3.5375+ *x 0.0125
  SPI_WriteData(0x6d); // 5D

  SPI_WriteComm(0xB1); // VCOM amplitude setting
  SPI_WriteData(0x37); //

  SPI_WriteComm(0xB2); // VGH Voltage setting
  SPI_WriteData(0x81); // 12V

  SPI_WriteComm(0xB3);
  SPI_WriteData(0x80);

  SPI_WriteComm(0xB5); // VGL Voltage setting
  SPI_WriteData(0x43); //-8.3V

  SPI_WriteComm(0xB7);
  SPI_WriteData(0x85);

  SPI_WriteComm(0xB8);
  SPI_WriteData(0x20);

  SPI_WriteComm(0xC1);
  SPI_WriteData(0x78);

  SPI_WriteComm(0xC2);
  SPI_WriteData(0x78);

  SPI_WriteComm(0xD0);
  SPI_WriteData(0x88);

  SPI_WriteComm(0xE0);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x02);

  SPI_WriteComm(0xE1);
  SPI_WriteData(0x03);
  SPI_WriteData(0xA0);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x04);
  SPI_WriteData(0xA0);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x20);
  SPI_WriteData(0x20);

  SPI_WriteComm(0xE2);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xE3);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x11);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xE4);
  SPI_WriteData(0x22);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xE5);
  SPI_WriteData(0x05);
  SPI_WriteData(0xEC);
  SPI_WriteData(0xA0);
  SPI_WriteData(0xA0);
  SPI_WriteData(0x07);
  SPI_WriteData(0xEE);
  SPI_WriteData(0xA0);
  SPI_WriteData(0xA0);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xE6);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x11);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xE7);
  SPI_WriteData(0x22);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xE8);
  SPI_WriteData(0x06);
  SPI_WriteData(0xED);
  SPI_WriteData(0xA0);
  SPI_WriteData(0xA0);
  SPI_WriteData(0x08);
  SPI_WriteData(0xEF);
  SPI_WriteData(0xA0);
  SPI_WriteData(0xA0);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xEB);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x40);
  SPI_WriteData(0x40);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);

  SPI_WriteComm(0xED);
  SPI_WriteData(0xFF);
  SPI_WriteData(0xFF);
  SPI_WriteData(0xFF);
  SPI_WriteData(0xBA);
  SPI_WriteData(0x0A);
  SPI_WriteData(0xBF);
  SPI_WriteData(0x45);
  SPI_WriteData(0xFF);
  SPI_WriteData(0xFF);
  SPI_WriteData(0x54);
  SPI_WriteData(0xFB);
  SPI_WriteData(0xA0);
  SPI_WriteData(0xAB);
  SPI_WriteData(0xFF);
  SPI_WriteData(0xFF);
  SPI_WriteData(0xFF);

  SPI_WriteComm(0xEF);
  SPI_WriteData(0x10);
  SPI_WriteData(0x0D);
  SPI_WriteData(0x04);
  SPI_WriteData(0x08);
  SPI_WriteData(0x3F);
  SPI_WriteData(0x1F);

  SPI_WriteComm(0xFF);
  SPI_WriteData(0x77);
  SPI_WriteData(0x01);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x13);

  SPI_WriteComm(0xEF);
  SPI_WriteData(0x08);

  SPI_WriteComm(0xFF);
  SPI_WriteData(0x77);
  SPI_WriteData(0x01);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);
  SPI_WriteData(0x00);

  SPI_WriteComm(0x11);

  mdelay(120);

  // SPI_WriteComm(0x23);

  SPI_WriteComm(0x29);

  SPI_WriteComm(0x36);
  SPI_WriteData(0x08);

  SPI_WriteComm(0x3A);
  SPI_WriteData(
      0x66); // 55/50=16bit(RGB565);66=18bit(RGB666);77或默认不写3AH是=24bit(RGB888)

  printk("st7701s init finished!!!");
}

/*
 * @description        : 打开设备
 * @param - inode     : 传递给驱动的inode
 * @param - filp     : 设备文件，file结构体有个叫做private_data的成员变量
 *                       一般在open的时候将private_data指向设备结构体。
 * @return             : 0 成功;其他 失败
 */
static int st7701_open(struct inode *inode, struct file *filp) { return 0; }

/*
 * @description        : 从设备读取数据
 * @param - filp     : 要打开的设备文件(文件描述符)
 * @param - buf     : 返回给用户空间的数据缓冲区
 * @param - cnt     : 要读取的数据长度
 * @param - offt     : 相对于文件首地址的偏移
 * @return             : 读取的字节数，如果为负值，表示读取失败
 */
static ssize_t st7701_read(struct file *filp, char __user *buf, size_t cnt,
                           loff_t *offt) {
  return 0;
}

/*
 * @description        : 向设备写数据
 * @param - filp     : 设备文件，表示打开的文件描述符
 * @param - buf     : 要写给设备写入的数据
 * @param - cnt     : 要写入的数据长度
 * @param - offt     : 相对于文件首地址的偏移
 * @return             : 写入的字节数，如果为负值，表示写入失败
 */
static ssize_t st7701_write(struct file *filp, const char __user *buf,
                            size_t cnt, loff_t *offt) {

  return 0;
}

/*
 * @description        : 关闭/释放设备
 * @param - filp     : 要关闭的设备文件(文件描述符)
 * @return             : 0 成功;其他 失败
 */
static int st7701_release(struct inode *inode, struct file *filp) { return 0; }

/* 设备操作函数 */
static struct file_operations st7701_fops = {
    .owner = THIS_MODULE,
    .open = st7701_open,
    .read = st7701_read,
    .write = st7701_write,
    .release = st7701_release,
};

/*
 * @description    : 驱动出口函数
 * @param         : 无
 * @return         : 无
 */
static int __init st7701_init(void) {

  int retvalue = 0;

  ST7701S_Init();

  /* 6、注册字符设备驱动 */
  retvalue = register_chrdev(200, "st7701", &st7701_fops);
  if (retvalue < 0) {
    printk("register chrdev failed!\r\n");
    return -EIO;
  }
  return 0;
}

/*
 * @description    : 驱动出口函数
 * @param         : 无
 * @return         : 无
 */
static void __exit st7701_exit(void) {

  /* 注销字符设备驱动 */
  unregister_chrdev(200, "st7701");
}

module_init(st7701_init);
module_exit(st7701_exit);
MODULE_INFO(intree, "Y");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FanHuaCloud");
